# -*- coding: utf-8 -*-

from __future__ import with_statement

from flask import Flask
from mock import Mock
from dicthash.utils import Bunch
from dicthash.for_testing import captured_templates, TestFlask, TestGoogleDataStore

from auth.code import set_user, register


def setCurrentUser(email, user_id=None, is_admin=False):
    import os
    os.environ['USER_EMAIL'] = email or ''
    os.environ['USER_ID'] = user_id or ''
    os.environ['USER_IS_ADMIN'] = '1' if is_admin else '0'

def logoutCurrentUser():
    setCurrentUser(None, None)


class MyFlask(TestFlask):
    """ """
    TEMPLATES = {
        'auth/create_user.html': """ 
            %auth/create_user.html%
        """
    }
        
    
class TestBase(TestGoogleDataStore):
    """ """
    def setUp(self):
        """ """
        super(TestBase, self).setUp()
        
        self.app = MyFlask(__name__)
        self.app.config.update(
            SECRET_KEY = "12345"
        )
        self.app.before_request(set_user)
        
        self.user_class = Mock()
        
        class UserError(Exception):
            pass
        self.UserError = UserError
        
        register(self.app, '/login',
            {
                'user_class': self.user_class,
                'user_exceptions': {self.UserError: "fuckin error"},
                'default_destination': '/',
                'session_key_name': 'user_data',
                'user_name_validator': lambda name: (name, None) if len(name)>3 else (None, 'name is invalid')
            }
        )
    

class TestLoginHandler(TestBase):
    """ """
    def test_google_anonym(self):
        """ """
        res = self.app.test_client().get('/login/start?next=/abc')
        self.assertEqual(res.status_code, 302)
        
    def test_google_logged_no_app_user(self):
        """ """
        self.user_class.get_by_openid = Mock(return_value=None)
        
        with captured_templates(self.app) as tmpl_info:
            setCurrentUser("bar@foo.com")
            res = self.app.test_client().get('/login/start')
            
            self.assertEqual(res.status_code, 200)
            self.assertEqual(tmpl_info[0][0], "auth/create_user.html")
            self.assertTrue('next' in tmpl_info[0][1])
            
    def test_google_logged_app_user_exists(self):
        """ """
        self.user_class.get_by_openid = Mock(return_value=Bunch(name="foo", openid="foo@bar.com"))
        
        setCurrentUser("bar@foo.com")
        res = self.app.test_client().get('/login/start')
        
        self.assertEqual(res.status_code, 302)       


class TestCreateUserHandler(TestBase):
    """ """
    def test_google_anonym_get(self):
        """ """
        res = self.app.test_client().get('/login/create')
        self.assertEqual(res.status_code, 405)
        
    def test_google_anonym_post(self):
        """ """
        res = self.app.test_client().post('/login/create')
        self.assertEqual(res.status_code, 403)
        
    def test_google_logged_form_invalid(self):
        """ """
        with captured_templates(self.app) as tmpl_info:
            setCurrentUser("bar@foo.com")
            res = self.app.test_client().post('/login/create', data={'name': 'a'})
            
            self.assertEqual(res.status_code, 200)
            self.assertEqual(tmpl_info[0][0], "auth/create_user.html")
            self.assertTrue('name' in tmpl_info[0][1])
            self.assertTrue('error' in tmpl_info[0][1])
            
    def test_google_logged_exception_in_db(self):
        """ """
        def make_error():
            raise TypeError('aaaAAA!!!!')
        app_user = Mock()
        app_user.put = Mock(side_effect=make_error)
        self.user_class.new = Mock(return_value=app_user)
         
        with captured_templates(self.app) as tmpl_info:
            setCurrentUser("bar@foo.com")
            res = self.app.test_client().post('/login/create', data={'name': 'test'})
            
            self.assertEqual(res.status_code, 500)
            self.assertEqual(len(tmpl_info), 0)
            
    def test_google_logged_user_exception(self):
        """ """
        def make_error():
            raise self.UserError
        app_user = Mock()
        app_user.put = Mock(side_effect=make_error)
        self.user_class.new = Mock(return_value=app_user)
         
        with captured_templates(self.app) as tmpl_info:
            setCurrentUser("bar@foo.com")
            res = self.app.test_client().post('/login/create', data={'name': 'test'})
            
            self.assertEqual(res.status_code, 200)
            self.assertEqual(tmpl_info[0][0], "auth/create_user.html")
            self.assertEqual(tmpl_info[0][1]['error'], "fuckin error")
            
    def test_google_logged_ok(self):
        """ """
        app_user = Mock(); app_user.name = 'test'; app_user.openid = 'foo@bar.com'
        self.user_class.new = Mock(return_value=app_user)
        
        with captured_templates(self.app) as tmpl_info:
            setCurrentUser("bar@foo.com")
            res = self.app.test_client().post('/login/create', data={'name': 'test'})
            
            self.assertEqual(len(tmpl_info), 0)
            self.assertEqual(res.status_code, 302)
            app_user.put.assert_called_once_with()
            

class TestLoginGreateLogoutLogin(TestBase):
    """
    1. login as 'foo@bar.com'
    """
    pass      